﻿using System;
using System.Diagnostics;
using System.Text;

namespace AMEE.BeinControl
{
    /// <summary>
    /// The Message protocol with constants and factory methods.
    /// </summary>
    class Protocol
    {

        #region Constants

        /// <summary>The start string of every Message</summary>
        public static readonly String MSG_BeginOfMsg = "$:";
        /// <summary>The end string of every Message</summary>
        public static readonly String MSG_EndOfMsg = ";";
        /// <summary>The parameter delimiter of every Message</summary>
        public static readonly String MSG_Delimiter = ":";
        /// <summary>'§d' - Placeholder of a digit</summary>
        public static readonly String MSG_Digit = "§d";
        /// <summary>'§s' - Placeholder of a +/- sign</summary>
        public static readonly String MSG_Sign = "§s";

        /// <summary>The <i>"Done"</i> response</summary>
        public static readonly String RSP_Done = MSG_BeginOfMsg + "Done" + MSG_EndOfMsg;


        /// <summary>The command <i>park position</i></summary>
        public static readonly String CMD_ParkPosition = MSG_BeginOfMsg + "P" + MSG_Delimiter + "P" + MSG_EndOfMsg;
        /// <summary>The expected response on <i>park position</i></summary>
        public static readonly String RSP_ParkPosition = RSP_Done;

        /// <summary>The command <i>stop all</i></summary>
        public static readonly String CMD_StopAll = MSG_BeginOfMsg + "S" + MSG_Delimiter + "S" + MSG_Delimiter + "S" + MSG_EndOfMsg;
        /// <summary>The expected response on <i>stop all</i></summary>
        public static readonly String RSP_StopAll = MSG_BeginOfMsg + "FullStop" + MSG_EndOfMsg;

        /// <summary>The command <i>Move to point (x,y,z)</i>, filled with placeholders for the arguments.</summary>
        public static readonly String CMD_Move2Point =
            MSG_BeginOfMsg + "M" + MSG_Delimiter + "F" + MSG_Delimiter +
            MSG_Sign + MSG_Digit + MSG_Digit + MSG_Digit + MSG_Digit + MSG_Delimiter + // x in mm
            MSG_Sign + MSG_Digit + MSG_Digit + MSG_Digit + MSG_Digit + MSG_Delimiter + // y in mm
            MSG_Sign + MSG_Digit + MSG_Digit + MSG_Digit + MSG_Digit + MSG_Delimiter + // z in mm
            MSG_Digit + MSG_Digit + MSG_Digit + MSG_Digit +                            // speed up to 7333
            MSG_EndOfMsg;
        /// <summary>The expected response on <i>Move to point</i></summary>
        public static readonly String RSP_Move2Point = RSP_Done;

        #endregion


        #region Factory Methods

        /// <summary>
        /// Gets the command string for <i>Stop All</i>.
        /// </summary>
        /// <returns>the command string for <i>Stop All</i></returns>
        public static String GetCommandStopAll() {
            return Protocol.CMD_StopAll;
        }

        /// <summary>
        /// Gets the command string for <i>ParkPosition</i>.
        /// </summary>
        /// <returns>the command string for <i>ParkPosition</i>.</returns>
        public static String GetCommandParkPosition() {
            return Protocol.CMD_ParkPosition;
        }

        /// <summary>
        /// Gets the command string for <i>'Move to Point'</i>.
        /// </summary>
        /// <param name="x">-10,000 &lt; xVal &lt; 10,000</param>
        /// <param name="y">-10,000 &lt; yVal &lt; 10,000</param>
        /// <param name="z">-10,000 &lt; zVal &lt; 10,000</param>
        /// <returns>The Move2Point Command "$:M:F:sxxxx:syyyy:szzzz:7333;", where s stands for +/-. Null, if an argument is invalid.</returns>
        public static String GetCommandMove2Point(int x, int y, int z) {
            int[] args = { x, y, z };
            if (! validatePosArgs(x, y, z)) {
                Debug.WriteLine(String.Format("GetCommandPosition({0}, {1}, {2}) have invalid argument.", x, y, z), "Warning Protocol");
                return null;
            }
            // 4stellige Zahlen (führende Null) mit +/-
            string[] xyz = {  (x>=0 ? "+" : "") + x.ToString("D4"), 
                              (y>=0 ? "+" : "") + y.ToString("D4"), 
                              (z>=0 ? "+" : "") + z.ToString("D4") };
            StringBuilder sb = new StringBuilder();
            sb.Append(MSG_BeginOfMsg).Append("M").Append(MSG_Delimiter).Append("F").Append(MSG_Delimiter);
            sb.Append(xyz[0]).Append(MSG_Delimiter).Append(xyz[1]).Append(MSG_Delimiter).Append(xyz[2]);
            sb.Append(MSG_Delimiter).Append("7333");
            sb.Append(MSG_EndOfMsg);
            return sb.ToString();
        }

        #endregion


        #region private Helpers

        /// <summary>
        /// Validates the position arguments, if they in [-9999, 9999] inklusive.
        /// </summary>
        /// <param name="ints">The int Vals to validate.</param>
        /// <returns>true, if all arguments are valid.</returns>
        static bool validatePosArgs(params int[] ints) {
            foreach (int i in ints) {
                if (i < -9999)
                    return false;
                else if (i > 9999)
                    return false;
            }
            return true;
        }

        #endregion

    }
}
